/**
 * @file counter.c
 * @author your name (you@domain.com)
 * @brief
 * @version 0.1
 * @date 2025-07-03
 *
 * @copyright Copyright (c) 2025
 *
 */
#include "counter.h"

/* 加计数器逻辑 (SInt) */
Bool CTU_SInt(Bool CU, Bool R, SInt *PV, SInt *CV, CTU_SINT* counter) {
    if (!PV || !CV || !counter) {
        return false;
    }

    // Step1: 复位逻辑
    if (R || counter->R) {
        counter->CV = 0;
        counter->QU = false;
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CU = CU;
        return counter->QU;
    }

    // Step2: LD逻辑
    if (counter->LD) {
        counter->CV = counter->PV;
        counter->QU = (counter->CV >= counter->PV);
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CU = CU;
        return counter->QU;
    }

    // Step3: 上升沿计数
    if (CU && !counter->last_CU) {
        if (counter->CV < INT8_MAX) {
            counter->CV++;
        } else {
            counter->CV = INT8_MAX;
        }
    }

    // Step4: 更新输出
    counter->QU = (counter->CV >= counter->PV);
    *CV = counter->CV;
    *PV = counter->PV;
    counter->last_CU = CU;

    return counter->QU;
}

/* CTU_Int */
Bool CTU_Int(Bool CU, Bool R, Int *PV, Int *CV, CTU_INT* counter) {
    if (!PV || !CV || !counter) return false;

    if (R || counter->R) {
        counter->CV = 0;
        counter->QU = false;
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CU = CU;
        return counter->QU;
    }

    if (counter->LD) {
        counter->CV = counter->PV;
        counter->QU = (counter->CV >= counter->PV);
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CU = CU;
        return counter->QU;
    }

    if (CU && !counter->last_CU) {
        if (counter->CV < INT16_MAX) counter->CV++;
        else counter->CV = INT16_MAX;
    }

    counter->QU = (counter->CV >= counter->PV);
    *CV = counter->CV;
    *PV = counter->PV;
    counter->last_CU = CU;

    return counter->QU;
}

/* CTU_DInt */
Bool CTU_DInt(Bool CU, Bool R, DInt *PV, DInt *CV, CTU_DINT* counter) {
    if (!PV || !CV || !counter) return false;

    if (R || counter->R) {
        counter->CV = 0;
        counter->QU = false;
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CU = CU;
        return counter->QU;
    }

    if (counter->LD) {
        counter->CV = counter->PV;
        counter->QU = (counter->CV >= counter->PV);
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CU = CU;
        return counter->QU;
    }

    if (CU && !counter->last_CU) {
        if (counter->CV < INT32_MAX) counter->CV++;
        else counter->CV = INT32_MAX;
    }

    counter->QU = (counter->CV >= counter->PV);
    *CV = counter->CV;
    *PV = counter->PV;
    counter->last_CU = CU;

    return counter->QU;
}

/* CTU_USInt */
Bool CTU_USInt(Bool CU, Bool R, USInt *PV, USInt *CV, CTU_USINT* counter) {
    if (!PV || !CV || !counter) return false;

    if (R || counter->R) {
        counter->CV = 0;
        counter->QU = false;
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CU = CU;
        return counter->QU;
    }

    if (counter->LD) {
        counter->CV = counter->PV;
        counter->QU = (counter->CV >= counter->PV);
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CU = CU;
        return counter->QU;
    }

    if (CU && !counter->last_CU) {
        if (counter->CV < UINT8_MAX) counter->CV++;
        else counter->CV = UINT8_MAX;
    }

    counter->QU = (counter->CV >= counter->PV);
    *CV = counter->CV;
    *PV = counter->PV;
    counter->last_CU = CU;

    return counter->QU;
}

/* CTU_UInt */
Bool CTU_UInt(Bool CU, Bool R, UInt *PV, UInt *CV, CTU_UINT* counter) {
    if (!PV || !CV || !counter) return false;

    if (R || counter->R) {
        counter->CV = 0;
        counter->QU = false;
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CU = CU;
        return counter->QU;
    }

    if (counter->LD) {
        counter->CV = counter->PV;
        counter->QU = (counter->CV >= counter->PV);
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CU = CU;
        return counter->QU;
    }

    if (CU && !counter->last_CU) {
        if (counter->CV < UINT16_MAX) counter->CV++;
        else counter->CV = UINT16_MAX;
    }

    counter->QU = (counter->CV >= counter->PV);
    *CV = counter->CV;
    *PV = counter->PV;
    counter->last_CU = CU;

    return counter->QU;
}

/* CTU_UDInt */
Bool CTU_UDInt(Bool CU, Bool R, UDInt *PV, UDInt *CV, CTU_UDINT* counter) {
    if (!PV || !CV || !counter) return false;

    if (R || counter->R) {
        counter->CV = 0;
        counter->QU = false;
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CU = CU;
        return counter->QU;
    }

    if (counter->LD) {
        counter->CV = counter->PV;
        counter->QU = (counter->CV >= counter->PV);
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CU = CU;
        return counter->QU;
    }

    if (CU && !counter->last_CU) {
        if (counter->CV < UINT32_MAX) counter->CV++;
        else counter->CV = UINT32_MAX;
    }

    counter->QU = (counter->CV >= counter->PV);
    *CV = counter->CV;
    *PV = counter->PV;
    counter->last_CU = CU;

    return counter->QU;
}

/* CTD_SINT */
Bool CTD_SInt(Bool CD, Bool LD, SInt *PV, SInt *CV, CTD_SINT* counter) {
    if (!PV || !CV || !counter) return false;

    // Step1: 复位逻辑
    if (counter->R) {
        counter->CV = 0;
        counter->QD = true;   // CV=0，QD置位
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CD = CD;
        return counter->QD;
    }

    // Step2: LD逻辑
    if (LD||counter->LD) {
        counter->CV = counter->PV;
        counter->QD = (counter->CV <= 0);
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CD = CD;
        return counter->QD;
    }

    // Step3: 上升沿递减
    if (CD && !counter->last_CD) {
        if (counter->CV > INT8_MIN) counter->CV--;
        else counter->CV = INT8_MIN;  // 饱和到最小值
    }

    // Step4: 更新输出
    counter->QD = (counter->CV <= 0);
    *CV = counter->CV;
    *PV = counter->PV;
    counter->last_CD = CD;

    return counter->QD;
}

/* CTD_INT */
Bool CTD_Int(Bool CD, Bool LD, Int *PV, Int *CV, CTD_INT* counter) {
    if (!PV || !CV || !counter) return false;

    if ( counter->R) {
        counter->CV = 0;
        counter->QD = true;
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CD = CD;
        return counter->QD;
    }

    if (LD || counter->LD) {
        counter->CV = counter->PV;
        counter->QD = (counter->CV <= 0);
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CD = CD;
        return counter->QD;
    }

    if (CD && !counter->last_CD) {
        if (counter->CV > INT16_MIN) counter->CV--;
        else counter->CV = INT16_MIN;
    }

    counter->QD = (counter->CV <= 0);
    *CV = counter->CV;
    *PV = counter->PV;
    counter->last_CD = CD;

    return counter->QD;
}

/* CTD_DINT */
Bool CTD_DInt(Bool CD, Bool LD, DInt *PV, DInt *CV, CTD_DINT* counter) {
    if (!PV || !CV || !counter) return false;

    if ( counter->R) {
        counter->CV = 0;
        counter->QD = true;
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CD = CD;
        return counter->QD;
    }

    if (LD || counter->LD) {
        counter->CV = counter->PV;
        counter->QD = (counter->CV <= 0);
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CD = CD;
        return counter->QD;
    }

    if (CD && !counter->last_CD) {
        if (counter->CV > INT32_MIN) counter->CV--;
        else counter->CV = INT32_MIN;
    }

    counter->QD = (counter->CV <= 0);
    *CV = counter->CV;
    *PV = counter->PV;
    counter->last_CD = CD;

    return counter->QD;
}

/* CTD_USINT */
Bool CTD_USInt(Bool CD, Bool LD, USInt *PV, USInt *CV, CTD_USINT* counter) {
    if (!PV || !CV || !counter) return false;

    if ( counter->R) {
        counter->CV = 0;
        counter->QD = true;
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CD = CD;
        return counter->QD;
    }

    if (LD||counter->LD) {
        counter->CV = counter->PV;
        counter->QD = (counter->CV == 0);
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CD = CD;
        return counter->QD;
    }

    if (CD && !counter->last_CD) {
        if (counter->CV > 0) counter->CV--;
        else counter->CV = 0;
    }

    counter->QD = (counter->CV == 0);
    *CV = counter->CV;
    *PV = counter->PV;
    counter->last_CD = CD;

    return counter->QD;
}

/* CTD_UINT */
Bool CTD_UInt(Bool CD, Bool LD, UInt *PV, UInt *CV, CTD_UINT* counter) {
    if (!PV || !CV || !counter) return false;

    if ( counter->R) {
        counter->CV = 0;
        counter->QD = true;
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CD = CD;
        return counter->QD;
    }

    if (LD||counter->LD) {
        counter->CV = counter->PV;
        counter->QD = (counter->CV == 0);
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CD = CD;
        return counter->QD;
    }

    if (CD && !counter->last_CD) {
        if (counter->CV > 0) counter->CV--;
        else counter->CV = 0;
    }

    counter->QD = (counter->CV == 0);
    *CV = counter->CV;
    *PV = counter->PV;
    counter->last_CD = CD;

    return counter->QD;
}

/* CTD_UDINT */
Bool CTD_UDInt(Bool CD, Bool LD, UDInt *PV, UDInt *CV, CTD_UDINT* counter) {
    if (!PV || !CV || !counter) return false;

    if ( counter->R) {
        counter->CV = 0;
        counter->QD = true;
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CD = CD;
        return counter->QD;
    }

    if (LD || counter->LD) {
        counter->CV = counter->PV;
        counter->QD = (counter->CV == 0);
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CD = CD;
        return counter->QD;
    }

    if (CD && !counter->last_CD) {
        if (counter->CV > 0) counter->CV--;
        else counter->CV = 0;
    }

    counter->QD = (counter->CV == 0);
    *CV = counter->CV;
    *PV = counter->PV;
    counter->last_CD = CD;

    return counter->QD;
}

/* CTUD_SInt */
Bool CTUD_SInt(Bool CU, Bool CD, Bool R, Bool LD,SInt *PV, SInt *CV, CTUD_SINT* counter) {
    if (!PV || !CV || !counter) return false;

    // Step1: 复位逻辑
    if (R || counter->R) {
        counter->CV = 0;
        counter->QU = false;
        counter->QD = true;
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CU = CU;
        counter->last_CD = CD;
        return counter->QU;
    }

    // Step2: LD逻辑
    if (LD || counter->LD) {
        counter->CV = counter->PV;
        counter->QU = (counter->CV >= counter->PV);
        counter->QD = (counter->CV <= 0);
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CU = CU;
        counter->last_CD = CD;
        return counter->QU;
    }

    // Step3: 上升沿加减计数
    Bool cu_rising = CU && !counter->last_CU;
    Bool cd_rising = CD && !counter->last_CD;

    if (cu_rising && !cd_rising) {
        if (counter->CV < INT8_MAX) counter->CV++;
        else counter->CV = INT8_MAX;
    } else if (!cu_rising && cd_rising) {
        if (counter->CV > INT8_MIN) counter->CV--;
        else counter->CV = INT8_MIN;
    }
    // 同时上升沿 -> 抵消，不变化

    // Step4: 更新输出
    counter->QU = (counter->CV >= counter->PV);
    counter->QD = (counter->CV <= 0);
    *CV = counter->CV;
    *PV = counter->PV;
    counter->last_CU = CU;
    counter->last_CD = CD;

    return counter->QU;
}

/* CTUD_Int */
Bool CTUD_Int(Bool CU, Bool CD, Bool R, Bool LD, Int *PV, Int *CV, CTUD_INT* counter) {
    if (!PV || !CV || !counter) return false;

    if (R || counter->R) {
        counter->CV = 0;
        counter->QU = false;
        counter->QD = true;
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CU = CU;
        counter->last_CD = CD;
        return counter->QU;
    }

    if (LD||counter->LD) {
        counter->CV = counter->PV;
        counter->QU = (counter->CV >= counter->PV);
        counter->QD = (counter->CV <= 0);
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CU = CU;
        counter->last_CD = CD;
        return counter->QU;
    }

    Bool cu_rising = CU && !counter->last_CU;
    Bool cd_rising = CD && !counter->last_CD;

    if (cu_rising && !cd_rising) {
        if (counter->CV < INT16_MAX) counter->CV++;
        else counter->CV = INT16_MAX;
    } else if (!cu_rising && cd_rising) {
        if (counter->CV > INT16_MIN) counter->CV--;
        else counter->CV = INT16_MIN;
    }

    counter->QU = (counter->CV >= counter->PV);
    counter->QD = (counter->CV <= 0);
    *CV = counter->CV;
    *PV = counter->PV;
    counter->last_CU = CU;
    counter->last_CD = CD;

    return counter->QU;
}

/* CTUD_DInt */
Bool CTUD_DInt(Bool CU, Bool CD, Bool R, Bool LD, DInt *PV, DInt *CV, CTUD_DINT* counter) {
    if (!PV || !CV || !counter) return false;

    if (R || counter->R) {
        counter->CV = 0;
        counter->QU = false;
        counter->QD = true;
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CU = CU;
        counter->last_CD = CD;
        return counter->QU;
    }

    if (LD||counter->LD) {
        counter->CV = counter->PV;
        counter->QU = (counter->CV >= counter->PV);
        counter->QD = (counter->CV <= 0);
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CU = CU;
        counter->last_CD = CD;
        return counter->QU;
    }

    Bool cu_rising = CU && !counter->last_CU;
    Bool cd_rising = CD && !counter->last_CD;

    if (cu_rising && !cd_rising) {
        if (counter->CV < INT32_MAX) counter->CV++;
        else counter->CV = INT32_MAX;
    } else if (!cu_rising && cd_rising) {
        if (counter->CV > INT32_MIN) counter->CV--;
        else counter->CV = INT32_MIN;
    }

    counter->QU = (counter->CV >= counter->PV);
    counter->QD = (counter->CV <= 0);
    *CV = counter->CV;
    *PV = counter->PV;
    counter->last_CU = CU;
    counter->last_CD = CD;

    return counter->QU;
}

/* CTUD_USInt */
Bool CTUD_USInt(Bool CU, Bool CD, Bool R, Bool LD, USInt *PV, USInt *CV, CTUD_USINT* counter) {
    if (!PV || !CV || !counter) return false;

    if (R || counter->R) {
        counter->CV = 0;
        counter->QU = false;
        counter->QD = true;
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CU = CU;
        counter->last_CD = CD;
        return counter->QU;
    }

    if (LD||counter->LD) {
        counter->CV = counter->PV;
        counter->QU = (counter->CV >= counter->PV);
        counter->QD = (counter->CV == 0);
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CU = CU;
        counter->last_CD = CD;
        return counter->QU;
    }

    Bool cu_rising = CU && !counter->last_CU;
    Bool cd_rising = CD && !counter->last_CD;

    if (cu_rising && !cd_rising) {
        if (counter->CV < UINT8_MAX) counter->CV++;
        else counter->CV = UINT8_MAX;
    } else if (!cu_rising && cd_rising) {
        if (counter->CV > 0) counter->CV--;
        else counter->CV = 0;
    }

    counter->QU = (counter->CV >= counter->PV);
    counter->QD = (counter->CV == 0);
    *CV = counter->CV;
    *PV = counter->PV;
    counter->last_CU = CU;
    counter->last_CD = CD;

    return counter->QU;
}

/* CTUD_UInt */
Bool CTUD_UInt(Bool CU, Bool CD, Bool R, Bool LD, UInt *PV, UInt *CV, CTUD_UINT* counter) {
    if (!PV || !CV || !counter) return false;

    if (R || counter->R) {
        counter->CV = 0;
        counter->QU = false;
        counter->QD = true;
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CU = CU;
        counter->last_CD = CD;
        return counter->QU;
    }

    if (LD||counter->LD) {
        counter->CV = counter->PV;
        counter->QU = (counter->CV >= counter->PV);
        counter->QD = (counter->CV == 0);
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CU = CU;
        counter->last_CD = CD;
        return counter->QU;
    }

    Bool cu_rising = CU && !counter->last_CU;
    Bool cd_rising = CD && !counter->last_CD;

    if (cu_rising && !cd_rising) {
        if (counter->CV < UINT16_MAX) counter->CV++;
        else counter->CV = UINT16_MAX;
    } else if (!cu_rising && cd_rising) {
        if (counter->CV > 0) counter->CV--;
        else counter->CV = 0;
    }

    counter->QU = (counter->CV >= counter->PV);
    counter->QD = (counter->CV == 0);
    *CV = counter->CV;
    *PV = counter->PV;
    counter->last_CU = CU;
    counter->last_CD = CD;

    return counter->QU;
}

/* CTUD_UDInt */
Bool CTUD_UDInt(Bool CU, Bool CD, Bool R, Bool LD, UDInt *PV, UDInt *CV, CTUD_UDINT* counter) {
    if (!PV || !CV || !counter) return false;

    if (R || counter->R) {
        counter->CV = 0;
        counter->QU = false;
        counter->QD = true;
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CU = CU;
        counter->last_CD = CD;
        return counter->QU;
    }

    if (LD||counter->LD) {
        counter->CV = counter->PV;
        counter->QU = (counter->CV >= counter->PV);
        counter->QD = (counter->CV == 0);
        *CV = counter->CV;
        *PV = counter->PV;
        counter->last_CU = CU;
        counter->last_CD = CD;
        return counter->QU;
    }

    Bool cu_rising = CU && !counter->last_CU;
    Bool cd_rising = CD && !counter->last_CD;

    if (cu_rising && !cd_rising) {
        if (counter->CV < UINT32_MAX) counter->CV++;
        else counter->CV = UINT32_MAX;
    } else if (!cu_rising && cd_rising) {
        if (counter->CV > 0) counter->CV--;
        else counter->CV = 0;
    }

    counter->QU = (counter->CV >= counter->PV);
    counter->QD = (counter->CV == 0);
    *CV = counter->CV;
    *PV = counter->PV;
    counter->last_CU = CU;
    counter->last_CD = CD;

    return counter->QU;
}
